package models

import (
	"errors"
	"fmt"
	"log"
	"time"

	"gitee.com/laofa1/play/k_conf_mng/kconf_backend/pkg/util"
	"gorm.io/gorm"
)

type Auth struct {
	ID        uint64    `gorm:"primaryKey" json:"user_id"`
	LoginName string    `json:"login_name"`
	UserName  string    `json:"user_name"`
	Password  string    `json:"password"`
	Role      string    `json:"role"`
	IsEnabled bool      `json:"isEnabled"`
	CreatedAt time.Time `json:"createdAt"`
}

func CheckAuth(loginName, password string) (bool, Auth) {
	var auth Auth
	db.Where(&Auth{LoginName: loginName}).First(&auth)
	if auth.Password != "" {
		if auth.IsEnabled {
			if util.VerifyPassword(auth.Password, []byte(password)) {
				return true, auth
			}
			log.Println("verify password fail")
			return false, auth
		}
		log.Printf("user: %s is not enabled", auth.LoginName)
		return false, auth
	}
	log.Println("check auth, get blank password, indicates use not exists")
	return false, auth
}

func GetUser(userID uint64) (Auth, error) {
	user := Auth{}
	result := db.First(&user, userID)
	if result.Error != nil {
		return user, result.Error
	}
	return user, nil
}

func GetAllUsers() ([]Auth, error) {
	users := []Auth{}
	result := db.Find(&users)
	if result.Error != nil {
		log.Println(result.Error)
		return nil, result.Error
	}
	return users, nil
}

func CreateAdmin(loginName, userName, password string) error {
	password, err := util.EncryptPassword([]byte(password))
	if err != nil {
		return err
	}

	user := Auth{
		LoginName: loginName,
		UserName:  userName,
		Role:      "admin",
		Password:  password,
		IsEnabled: true,
	}

	result := db.Create(&user)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

func CreateUser(loginName, userName, password string) error {
	password, err := util.EncryptPassword([]byte(password))
	if err != nil {
		return err
	}

	user := Auth{
		LoginName: loginName,
		UserName:  userName,
		Role:      "user",
		Password:  password,
		IsEnabled: true,
	}

	result := db.Create(&user)
	if result.Error != nil {
		log.Println(result.Error)
		return result.Error
	}
	return nil
}

func DisableUser(userID uint64) error {
	result := db.Model(&Auth{}).Where("id = ?", userID).Update("is_enabled", false)
	if result.Error != nil {
		log.Println(result.Error)
		return result.Error
	} else if result.RowsAffected != 1 {
		errMsg := fmt.Sprintf("fail to disabel userID: %d, affterd row is not 1", userID)
		log.Println(errMsg)
		return errors.New(errMsg)
	}
	return nil
}

func EnableUser(userID uint64) error {
	result := db.Model(&Auth{}).Where("id = ?", userID).Update("is_enabled", true)
	if result.Error != nil {
		log.Println(result.Error)
		return result.Error
	} else if result.RowsAffected != 1 {
		errMsg := fmt.Sprintf("fail to enabel userID: %d, affterd row is not 1", userID)
		log.Println(errMsg)
		return errors.New(errMsg)
	}
	return nil
}

func ChangeRole(userID uint64, role string) error {
	var result *gorm.DB
	switch role {
	case "admin":
		result = db.Model(&Auth{}).Where("id = ?", userID).Update("role", "admin")
	case "user":
		result = db.Model(&Auth{}).Where("id = ?", userID).Update("role", "user")
	default:
		log.Println("only admin or user supported in change role")
		return errors.New("only admin or user supported in change role")
	}

	if result.Error != nil {
		log.Println(result.Error)
		return result.Error
	} else if result.RowsAffected != 1 {
		errMsg := fmt.Sprintf("fail to disabel userID: %d, affterd row is not 1", userID)
		log.Println(errMsg)
		return errors.New(errMsg)
	}
	return nil
}

// SetPassword to reset user password by admin user
func SetPassword(userID uint64, password string) error {
	password, err := util.EncryptPassword([]byte(password))
	if err != nil {
		return err
	}
	result := db.Model(&Auth{}).Where("id = ?", userID).Update("password", password)
	if result.Error != nil {
		log.Println(result.Error)
		return result.Error
	}
	return nil
}
